package com.rongji.dfish.framework.dao;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.rongji.dfish.base.Page;

public class PubCommonDAOImpl extends HibernateDaoSupport implements
		PubCommonDAO {
	/**
	 * 运行时间阀值
	 */
	private long executeThreshold = 2000L;
	
	public long getExecuteThreshold() {
		return executeThreshold;
	}

	public void setExecuteThreshold(long executeThreshold) {
		this.executeThreshold = executeThreshold;
	}

	private static boolean debug = false;
	
	public boolean isDebug() {
		return debug;
	}

	public void setDebug(boolean debug) {
		PubCommonDAOImpl.debug = debug;
	}
	
	private static final Log LOG=LogFactory.getLog(PubCommonDAOImpl.class);
	public List<?> getQueryList(final String strSql, final Object... object) {
		long beginTimeMillis=System.currentTimeMillis();
		final HibernateTemplate template = getHibernateTemplate();
		template.setCacheQueries(true);
		// return template.find(strSql,object);
		// ?????timeStamp???????????????????find
		HibernateCallback action = new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(strSql);
				if (object != null) {  
					for (int i = 0; i < object.length; i++) {
						setArgument(query, i, object[i]);
					}
				}

				ArrayList<?> arrayList = (ArrayList<?>) query.list();

				return arrayList;
			}
		};

		List<?> list= (List<?>) template.execute(action);
		long endTimeMillis=System.currentTimeMillis();
		long costTime = endTimeMillis - beginTimeMillis;
		if (costTime > executeThreshold) {
			LOG.warn("execute sql[" + strSql + "] cost: " + costTime + "ms");
		}
		return list;
	}

	public int deleteSQL(String strSql, Object... object) {
		long beginTimeMillis = System.currentTimeMillis();
		List<?> list = getQueryList(strSql, object);
		if (list != null) {
			getHibernateTemplate().deleteAll(list);
		}
		long endTimeMillis = System.currentTimeMillis();
		long costTime = endTimeMillis - beginTimeMillis;
		if (costTime > executeThreshold) {
			LOG.warn("execute sql[" + strSql + "] cost: " + costTime + "ms");
		}
		return list == null ? 0 : list.size();
	}

	public void delete(Object obj) {
		if (obj != null) {
			getHibernateTemplate().delete(obj);
		}
	}

	public void save(final Object object) {
		if (object != null) {
			getHibernateTemplate().save(object);
		}
	}

	public void update(final Object object) {
		if (object != null) {
			getHibernateTemplate().update(object);
		}
	}

	protected static final void setArgument(Query query, int index, Object o) {
		if (o instanceof java.lang.String) {
			query.setString(index, (String) o);
		} else if (o instanceof java.lang.Integer) {
			query.setInteger(index, ((Integer) o).intValue());
		} else if (o instanceof java.util.Date) {
			query.setTimestamp(index, (java.util.Date) o);
		} else if (o instanceof java.lang.Boolean) {
			query.setBoolean(index, ((Boolean) o).booleanValue());
		} else if (o instanceof java.lang.Byte) {
			query.setByte(index, ((Byte) o).byteValue());
		} else if (o instanceof java.lang.Long) {
			query.setLong(index, ((Long) o).longValue());
		} else if (o instanceof java.lang.Double) {
			query.setDouble(index, ((Double) o).doubleValue());
		} else if (o instanceof java.lang.Float) {
			query.setFloat(index, ((Float) o).floatValue());
		} else if (o instanceof java.lang.Number) {
			query.setBigDecimal(index, new java.math.BigDecimal(((Number) o)
					.doubleValue()));
		} else {
			query.setString(index, o.toString());
		}

	}

	public void evictObject(final Object object) {
		if (object != null) {
			getHibernateTemplate().evict(object);
		}
	}

	public List<?> getQueryList(final String strSql, final Page page, final Object... object) {
	    if (page == null) {
	        return getQueryList(strSql, object);
	    } else {
	        if (page.getAutoRowCount() == null) {
	            page.setAutoRowCount(true);
	        }
	    }
	    return getQueryList(strSql, page, page.getAutoRowCount(), object);
	}
	public List<?> getQueryList(final String strSql, final Page page,
			final boolean autoGetRowCount, final Object... object) {
		final HibernateTemplate template = getHibernateTemplate();
		template.setCacheQueries(true);
		long beginTimeMillis = System.currentTimeMillis();
		HibernateCallback action = new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				// ??b???
				Query query = session.createQuery(strSql);
				// ???��????��?
				if (object != null) {

					// ???????��?
					for (int i = 0; i < object.length; i++) {
						setArgument(query, i, object[i]);
					}
				}
				if (autoGetRowCount) {
					// ???????

					String upperSQL = strSql.toUpperCase();
					if (upperSQL.indexOf("DISTINCT") < 0) { // ?????query????setRowCount?????
						int i = 0;
						String strHql4cout = strSql;
						// strHql4cout count ?????????from????????order by ????????.
						if ((i = upperSQL.indexOf(" FROM ")) >= 0) {
							strHql4cout = strSql.substring(i);
							upperSQL = upperSQL.substring(i);
						}
						i = upperSQL.indexOf("ORDER ");
						outter: while (i > 0) {
							// ?????????? 0-N????+BY?????ORDER BY???
							char[] ca = upperSQL.toCharArray();
							int point = i + 6;
							while (point < ca.length - 3) {
								if (ca[point] == 'B') {
									if (ca[point + 1] == 'Y'
											&& (ca[point + 2] == ' ' || ca[point + 2] == '(')) {
										strHql4cout = strHql4cout.substring(0,
												i);
										break outter;
									}
								} else if (ca[point] == ' ') {
									point++;
								} else {
									break;
								}
							}
							int k = upperSQL.substring(i + 6).indexOf("ORDER ");
							if (k < 0) {
								break;
							} else {
								i = i + 6 + k;
							}

						}

						// strHql4cout ?from?????
						Query query1 = session.createQuery("select count(*) "
								+ strHql4cout);
						// ???��????��?
						if (object != null) {

							// ???????��?
							for (int k = 0; k < object.length; k++) {
								setArgument(query1, k, object[k]);
							}
						}

						List<?> arrayList = query1.list();
						Integer inte = ((Number) arrayList.get(0)).intValue();
						page.setRowCount(inte.intValue());
					} else { // ?????query????setRowCount?????
						List<?> arrayList = query.list();
						page.setRowCount(arrayList.size());
					}
				}
				// ??????????
				if (page.getCurrentPage() != 0) {
					int pageno = page.getCurrentPage();
					query.setFirstResult((pageno - 1) * (page.getPageSize()));
					query.setMaxResults(page.getPageSize());
				}

				List<?> arrayList = query.list();
				return arrayList;
			}
		};
		List<?> result = (List<?>) template.execute(action);
		long endTimeMillis = System.currentTimeMillis();
		long costTime = endTimeMillis - beginTimeMillis;
		if (costTime > executeThreshold) {
			LOG.warn("execute sql[" + strSql + "] cost: " + costTime + "ms");
		}
		// 当前记录数
		if (result != null) {
			page.setCurrentCount(result.size());
		}
		return result;
	}


	public Object queryAsAnObject(final String strSql, final Object... object){
		List<?> list=getQueryList(strSql,object);
		if(list.size()==0)return null;
		return list.get(0);
	}

	/**
	 * ????????HSQL????????????????????
	 * 
	 * @param queryString
	 * @param values
	 * @return
	 */
	public int bulkUpdate(String queryString, Object... values) {
		return getHibernateTemplate().bulkUpdate(queryString, values);
	}
}
